//  Created by zmyl on 2025/5/30.
//  Copyright © 2025 zmyl. All rights reserved.

#import "NetworkManager.h"
#import "Reachability.h"
#import "MBProgressHUD+Count.h"

@interface NetworkManager ()

@property (nonatomic, strong) AFHTTPSessionManager *httpManager;
/// 按 URL 存储 Task
@property (nonatomic, strong) NSMapTable<NSString *, NSMutableArray<NSURLSessionTask *> *> *taskMap;
@property (nonatomic, strong) dispatch_queue_t taskQueue;
@property (nonatomic,assign) CFAbsoluteTime startTime;

@end

@implementation NetworkManager

static NetworkManager * _sharedsingleton = nil;

#pragma mark - 网络的监听
+ (void)netWorkReachabilityObserver:(void(^)(AFNetworkReachabilityStatus resultStatus))block{
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        if (block) {
            block(status);
        }
    }];
    [manager startMonitoring];
}

+(instancetype)shared{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedsingleton = [[super allocWithZone:NULL]init];
    });
    return _sharedsingleton;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    return [NetworkManager shared];
}

- (id)copyWithZone:(nullable NSZone *)zone{
    return [NetworkManager shared];
}

- (id)mutableCopyWithZone:(nullable NSZone *)zone{
    return [NetworkManager shared];
}

-(id)copy{
    return self;
}

- (instancetype)init{
    if (self = [super init]) {
        _taskMap = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory
                                         valueOptions:NSPointerFunctionsStrongMemory];
        _taskQueue = dispatch_queue_create("com.network.taskMapQueue", DISPATCH_QUEUE_SERIAL);
    }
    return self;
}

#pragma mark - 创建请求者
- (AFHTTPSessionManager *)httpManager {
    if (!_httpManager) {
        _httpManager = [AFHTTPSessionManager manager];
        _httpManager.requestSerializer.timeoutInterval = AL_NETWORK_REQUEST_TIMEOUT;
        _httpManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", nil];
        _httpManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
        _httpManager.securityPolicy.allowInvalidCertificates = YES;
        [_httpManager.securityPolicy setValidatesDomainName:NO];
    }
    return _httpManager;
}

- (BOOL)isNetWorkAvailable{
    Reachability* reach = [Reachability reachabilityWithHostName:@"www.baidu.com"];
    NetworkStatus status = reach.currentReachabilityStatus;
    return status != NotReachable;
}

/// 检查有无网络(带提示)
-(BOOL)checkNetWorkAvailable{
    BOOL haveNetWork = [self isNetWorkAvailable];
    if (!haveNetWork) {
        [TPHUD showBriefMsg:@"没有网络哦，请检查网络设置"];
    }
    return haveNetWork;
}

- (void)cancelNetworkRequest{
    if (self.httpManager) {
        [self.httpManager.operationQueue cancelAllOperations];
    }
}

#pragma mark - 设置请求头
- (NSDictionary *)httpsHeaders{
    NSMutableDictionary *params = [[NSMutableDictionary alloc]initWithCapacity:0];

    NSString *authTokenStr = TPAPPDelegate.token;
    if (![NSString isEmpty:authTokenStr]) {
        [params setValue:[NSString stringWithFormat:@"Bearer %@", TPAPPDelegate.token] forKey:@"Authorization"];
    }
    
    //把时间添加到请求头
    long long nowTime = [NSDate getCurrentTimestampLong];
    NSString *ts = [NSString stringWithFormat:@"%lld",nowTime];
    NSString *currentTimeStr = [NSString dateStrWithMilliTimestamp:ts dataFormatterStr:DFYearMonthDayHoueMinutesSec];
    [params setValue:ts forKey:@"timeStamp"];
    [params setValue:currentTimeStr forKey:@"time"];
    return params;
}

- (RACSignal *)rac_requestWithModule:(RequestModule)module
                              method:(RequestMethod)method
                              urlStr:(NSString *)urlStr
                          parameters:(nullable NSDictionary *)params
                         showLoading:(BOOL)showLoading
                             showTip:(BOOL)showTip {
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [self loadHttpRequest:module
                       method:method
                       urlStr:urlStr
                   parameters:params
                      success:^(ResponseEntity *response) {
            [subscriber sendNext:response];
            [subscriber sendCompleted];
        }
                      failure:^(ResponseEntity *error) {
            NSDictionary *userInfo = @{
                kNetworkErrorResponseKey:error
            };
            [subscriber sendError:[NSError errorWithDomain:kNetworkRequestLoadFailed
                                                      code:error.flag
                                                  userInfo:userInfo]];
//            [subscriber sendCompleted];//这个地方不需要
        }
                  showLoading:showLoading
                      showTip:showTip];
        return [RACDisposable disposableWithBlock:^{
            [self cancelTasksForMethod:method url:urlStr];// 取消特定请求
        }];
    }];
}

- (void)loadHttpRequest:(RequestModule)moduleType
                 method:(RequestMethod)method
                 urlStr:(NSString *)urlStr
             parameters:(nullable NSDictionary*)parameters
                success:(void (^)(ResponseEntity *responseModel))success
                failure:(void (^)(ResponseEntity *errModel))failure
            showLoading:(BOOL)showLoading
                showTip:(BOOL)showTip{
    @weakify(self);
    // 1. 网络可用性检查
    if (![self isNetWorkAvailable]) {
        ResponseEntity *errModel = [ResponseEntity new];
        errModel.flag = -1000;
        errModel.message = @"没有网络哦，请检查网络设置";
        if (showTip) {
            [TPHUD showBriefMsg:@"没有网络哦，请检查网络设置"];
        }
        failure(errModel);
        return;
    }

    if (![urlStr isKindOfClass:[NSString class]] || urlStr.length == 0) {
        if (failure) {
            ResponseEntity *errModel = [ResponseEntity new];
            errModel.flag = -1001;
            errModel.message = @"请求路径无效";
            failure(errModel);
        }
        return;
    }

    // 2. 公共对象初始化
    NSDictionary *headers = [self httpsHeaders];

    NSString *baseUrl = [self moduleTypeForBaseUrl:moduleType];
    NSString *appendUrlStr = [baseUrl stringByAppendingString:urlStr];
    NSString *encodedURL = [appendUrlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];//注意这里的​URL编码方式
    NSString *methodName = [self methodNameForType:method]; //根据枚举返回字符串如@"GET"
    NSString *paramsJsonStr = [parameters jk_JSONString];
    NSString * logStr = [NSString stringWithFormat:@"\n接口调用=>\n类型：%@\n接口Url：%@\n参数：%@\n请求header：%@",methodName, encodedURL, paramsJsonStr, headers];
    NSLog(@"%@",logStr);
    ///这里是日志输出
#ifdef DEBUG
    [QMUIConsole log:logStr];
#endif

    // 3. 请求分发核心
    void (^successBlock)(NSURLSessionDataTask *, ResponseEntity *responseModel) = ^(NSURLSessionDataTask *task, id responseObject) {
        @strongify(self);
        if (showLoading) {
            [MBProgressHUD decrementActivityCount];
        }
        [self handleResponse:task response:responseObject method:method url:encodedURL showLoading:showLoading showTip:showTip success:success failure:failure];
    };

    void (^failureBlock)(NSURLSessionDataTask *, NSError *) = ^(NSURLSessionDataTask *task, NSError *error) {
        @strongify(self);
        if (showLoading) {
            [MBProgressHUD decrementActivityCount];
        }
        [self handleFailure:task error:error method:method url:encodedURL showLoading:showLoading showTip:showTip failure:failure];
    };

    // 记录请求开始时间
    self.startTime = CFAbsoluteTimeGetCurrent();

    if (method == RequestMethodGET) {
        _httpManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", nil];
        _httpManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        // 关键：自定义数组参数的序列化方式
        [_httpManager.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, id parameters, NSError *__autoreleasing *error) {
            NSMutableArray *components = [NSMutableArray array];
            [parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                if ([obj isKindOfClass:[NSArray class]]) {
                    // 数组参数处理：重复键不带 []
                    for (id value in obj) {
                        NSString *encodedKey = [key stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
                        NSString *encodedValue = [[value description] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
                        [components addObject:[NSString stringWithFormat:@"%@=%@", encodedKey, encodedValue]];
                    }
                } else {
                    // 非数组参数正常处理
                    NSString *encodedKey = [key stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
                    NSString *encodedValue = [[obj description] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
                    [components addObject:[NSString stringWithFormat:@"%@=%@", encodedKey, encodedValue]];
                }
            }];
            return [components componentsJoinedByString:@"&"];
        }];
    } else{
        _httpManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", nil];
        _httpManager.requestSerializer = [AFJSONRequestSerializer serializer];
    }

    NSURLSessionTask *requestTask = nil; // 用于保存返回的任务对象

    // 5. 根据请求类型分发
    switch (method) {
        case RequestMethodGET:
            requestTask = [self.httpManager GET:encodedURL
                                     parameters:parameters
                                        headers:headers
                                       progress:nil
                                        success:successBlock
                                        failure:failureBlock];
            break;

        case RequestMethodPOST:
            requestTask = [self.httpManager POST:encodedURL
                                      parameters:parameters
                                         headers:headers
                                        progress:nil
                                         success:successBlock
                                         failure:failureBlock];
            break;

        case RequestMethodPUT:
            requestTask = [self.httpManager PUT:encodedURL
                                     parameters:parameters
                                        headers:headers
                                        success:successBlock
                                        failure:failureBlock];
            break;

        case RequestMethodDELETE:
            requestTask = [self.httpManager DELETE:encodedURL
                                        parameters:parameters
                                           headers:headers
                                           success:successBlock
                                           failure:failureBlock];
            break;
    }

    // 将任务添加到任务队列中
    if (requestTask) {
        [self addTask:requestTask method:method url:encodedURL];
    }

    // 6. 加载状态显示
    if (showLoading) {
        [MBProgressHUD incrementActivityCount]; // 请求开始
    }
}

// MARK: - 响应处理封装
- (void)handleResponse:(NSURLSessionDataTask *)task
              response:(id)responseObject
                method:(RequestMethod)method
                   url:(NSString *)urlStr
           showLoading:(BOOL)showLoading
               showTip:(BOOL)showTip
               success:(void (^)(ResponseEntity *responseModel))success
               failure:(void (^)(ResponseEntity *errModel))failure{
    // 移除任务
    [self removeTask:task method:method url:urlStr];
//    if (showLoading) {
//        [MBProgressHUD decrementActivityCount];
//    }

    NSHTTPURLResponse *response = (NSHTTPURLResponse*)task.response;
    NSInteger statusCode = response.statusCode;

    // 计算耗时
    CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
    double duration = (endTime - self.startTime) * 1000.0;
    NSString *paramsJsonStr = [responseObject jk_JSONString];
    NSString *logStr = [NSString stringWithFormat:@"\n接口Url：%@\n状态码：statusCode=%ld\n耗时：%.2f毫秒\n返回数据=>%@",urlStr,statusCode,duration,paramsJsonStr];
    NSLog(@"%@", logStr);
#ifdef DEBUG
    [QMUIConsole log:logStr];
#endif

    if (statusCode == 200) {
        if (responseObject) {
            ResponseEntity *model = [ResponseEntity mj_objectWithKeyValues:responseObject];
            if (success) {
                success(model);
            }

            if (showTip && ![NSString isEmpty:model.message]) {
                [TPHUD showBriefMsg:model.message];
            }
        } else {
            ResponseEntity *errModel = [ResponseEntity new];
            errModel.flag = -1001;
            errModel.message = @"服务器开小差了!";
            failure(errModel);
        }
    } else{
        ResponseEntity *model = [ResponseEntity mj_objectWithKeyValues:responseObject];
        failure(model);
        //对 401/406/460 做处理判断
        [self handleAuthExpiredIfNeeded:model.flag showTip:showTip message:model.message];
    }
}

// MARK: - 错误处理封装
- (void)handleFailure:(NSURLSessionDataTask *)task
                error:(NSError *)error
               method:(RequestMethod)method
                  url:(NSString *)urlStr
          showLoading:(BOOL)showLoading
              showTip:(BOOL)showTip
              failure:(void (^)(ResponseEntity *errModel))failure {
    // 移除任务
    [self removeTask:task method:method url:urlStr];
//    if (showLoading) {
//        [MBProgressHUD decrementActivityCount];
//    }

    NSDictionary *erroInfo = error.userInfo;
    NSData *errorData = [erroInfo valueForKey:@"com.alamofire.serialization.response.error.data"];
    NSString *errorString = [[NSString alloc] initWithData:errorData encoding:NSUTF8StringEncoding];

    NSHTTPURLResponse * response = (NSHTTPURLResponse*)task.response;
    NSInteger statusCode = response.statusCode;

    if (![NSString isEmpty:errorString] && errorData) {
        NSLog(@"接口错误=>%@\n状态码statusCode=%ld\n错误信息:%@",urlStr,statusCode,errorString);
        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:errorData options:NSJSONReadingMutableContainers error:NULL];
        ResponseEntity *model = [ResponseEntity mj_objectWithKeyValues:dic];

        //对 401/406/460 做处理判断
        [self handleAuthExpiredIfNeeded:model.flag showTip:showTip message:model.message];

        failure(model);
    } else{
        NSString *errorReasonStr = error.localizedDescription;
        NSLog(@"接口错误=>%@\n状态码statusCode=>%ld\nhandleFailure错误打印为:%@",urlStr,statusCode,errorReasonStr);
        ResponseEntity *errModel = [ResponseEntity new];
        if (![NSString isEmpty:errorReasonStr]) {
            errModel.message = errorReasonStr;
        } else{
            errModel.message = [NSString stringWithFormat:@"请求失败，请稍后再试%ld",(long)error.code];
            [TPHUD showBriefMsg:[NSString stringWithFormat:@"请求失败，请稍后再试%ld",(long)error.code]];
        }
        failure(errModel);
    }
}

- (void)handleAuthExpiredIfNeeded:(NSInteger)flag showTip:(BOOL)showTip message:(NSString *)message{
    if (flag == 401 || flag == 406 || flag == 460) {
        [TPHUD showBriefMsg:@"登录状态过期，请重新登录"];
        [TPNotice postNotificationName:TPLogoutNotification object:nil];
    } else{
        if (showTip && ![NSString isEmpty:message]) {
            [TPHUD showBriefMsg:message];
        }
    }
}

// MARK: - 辅助方法
- (NSString *)methodNameForType:(RequestMethod)method {
    switch (method) {
        case RequestMethodGET: return @"GET";
        case RequestMethodPOST: return @"POST";
        case RequestMethodPUT: return @"PUT";
        case RequestMethodDELETE: return @"DELETE";
        default: return @"UNKNOWN";
    }
}

// MARK: - 辅助方法
- (NSString *)moduleTypeForBaseUrl:(RequestModule)type {
    switch (type) {
        case RequestModule_Cheese: return TPAPIConfig.baseUrl;
        case RequestModule_Inquiry: return TPAPIConfig.inquiryBaseUrl;
        case RequestModule_Simulation: return TPAPIConfig.simulationBaseUrl;
        case RequestModule_Anatomy: return TPAPIConfig.anatomyBaseUrl;
        case RequestModule_Megagame: return TPAPIConfig.megagame_platformBaseUrl;
        default: return TPAPIConfig.baseUrl;
    }
}

- (NSString *)generateTaskKeyForMethod:(RequestMethod)method url:(NSString *)url {
    return [NSString stringWithFormat:@"%@_%@", [self methodNameForType:method], url];
}

/// 封装线程安全操作
- (void)safeModifyTaskMap:(void (^)(void))block {
    dispatch_sync(self.taskQueue, block);
}

- (void)addTask:(NSURLSessionTask *)task method:(RequestMethod)method url:(NSString *)url {
    @weakify(self);
    [self safeModifyTaskMap:^{
        @strongify(self);
        NSString *key = [self generateTaskKeyForMethod:method url:url];
        NSMutableArray *tasks = (NSMutableArray *)[self.taskMap objectForKey:key] ?: [NSMutableArray new];
        [tasks addObject:task];
        [self.taskMap setObject:tasks forKey:key];
    }];
}

- (void)removeTask:(NSURLSessionTask *)task method:(RequestMethod)method url:(NSString *)url {
    @weakify(self);
    [self safeModifyTaskMap:^{
        @strongify(self);
        NSString *key = [self generateTaskKeyForMethod:method url:url];
        NSMutableArray *tasks = [self.taskMap objectForKey:key];
        [tasks removeObject:task];
        if (tasks.count == 0) {
            [self.taskMap removeObjectForKey:key];
        }
    }];
}

- (void)cancelTasksForMethod:(RequestMethod)method url:(NSString *)url {
    @weakify(self);
    [self safeModifyTaskMap:^{
        @strongify(self);
        NSString *key = [self generateTaskKeyForMethod:method url:url];
        NSMutableArray *tasks = (NSMutableArray *)[self.taskMap objectForKey:key];
        [tasks makeObjectsPerformSelector:@selector(cancel)]; // 批量取消
        [self.taskMap removeObjectForKey:key]; // 清理存储
    }];
}
@end
